
#include "SysDefine.hpp"
#include "MqttClient.hpp"
#include <termios.h> // 终端结构体
extern "C" {
// #include "luckfox_uart.h" // 官方驱动有点问题
}

#define US_DEV_PATH "/dev/ttyS3"
#define US_RECV_BUFF_LEN 4096

// 打开串口
int Uart_Open(const char * devPath)
{
    return open(devPath, O_RDWR | O_NOCTTY);
}

// 初始化串口，返回串口fd
int Uart_Init(const char * devPath, int baudrate)
{
    int fd = Uart_Open(devPath);
    if (fd < 0) {
        cout << "Failed to open serial port" << endl;
        return -1;
    }

    struct termios tty;
    memset(&tty, 0, sizeof(tty));
    if (tcgetattr(fd, &tty) != 0) {
        cout << "Error from tcgetattr" << endl;
        return -2;
    }

    cout << "Need set uart baudrate to " << baudrate << endl;
    speed_t speed = B9600; // 默认9600
    switch (baudrate) {
        case 1200: speed = B1200; break;
        case 4800: speed = B4800; break;
        case 38400: speed = B38400; break;
        case 57600: speed = B57600; break;
        case 115200: speed = B115200; break;
        case 230400: speed = B230400; break;
        case 460800: speed = B460800; break;
        case 921600: speed = B921600; break;
        default:
          cout << "[ERROR] Not support this baudrate: " << baudrate << endl;
    }

    cfsetospeed(&tty, speed);
    cfsetispeed(&tty, speed);
    cfmakeraw(&tty); // 设置为非规范模式，不需要等到回车符才read

    tty.c_cflag &= ~PARENB; // 无奇偶校验
    tty.c_cflag &= ~CSTOPB; // 1停止位
    tty.c_cflag &= ~CSIZE; // 8bit
    tty.c_cflag |= CS8;

    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
        cout << "Error from tcsetattr" << endl;
        return -3;
    }
    return fd;
}

// 串口写函数
int Uart_Write(int fd, const char *buff, uint buffSize)
{
    ssize_t bytes_written = write(fd, buff, buffSize);
    if (bytes_written < 0) {
        cout << "Error writing to serial port" << endl;
        close(fd);
    }
    return bytes_written;
}

// 阻塞函数，返回读取的字符数
int Uart_Read(int fd, char *buff, int buffSize)
{
    return read(fd, buff, buffSize);
}

// 关闭串口
void Uart_Deinit(int fd)
{
    close(fd);
}

// 等待消息，同步写串口线程
void* Thread_UartSync(void* arg)
{
  int serial_fd = Uart_Open(US_DEV_PATH);
  if (serial_fd < 0) {
      cout <<"Failed to open serial port." << endl;
      pthread_exit(0);
  }

  Uart_Write(serial_fd, "hello", strlen("hello"));

  // 监听消息队列
	zmq::context_t ctx;
  zmq::socket_t subSock(ctx, zmq::socket_type::sub);
  subSock.connect(ZMQ_US_MSG_URL);
	subSock.set(zmq::sockopt::subscribe, ZMQ_TOPIC_US_TX); // 订阅主题

	// 等待消息
  while (1) {
    vector<zmq::message_t> recv_msgs;
    zmq::recv_result_t res = zmq::recv_multipart(subSock, back_inserter(recv_msgs));
    if (res.has_value() != true || res.value() != 2) continue;
    if (recv_msgs[0].to_string() == ZMQ_TOPIC_US_TX) {
      const char* data = (const char*)recv_msgs[1].data();
      uint bytes = recv_msgs[1].size();

      cout << "uart tx: " << std::hex << std::showbase;
      for (uint i = 0; i < bytes; i++) cout << (int)data[i] << " ";
      cout << std::dec << endl;

      Uart_Write(serial_fd, data, bytes); // 发往串口
    }
  }
}

// 硬件串口处理线程
void* Thread_UartHandler(void* arg)
{
  cout << "[Thread] uart thread start" << endl;
	if (S_NOT_HAS("us-baud")) S_SET("us-baud", 115200);

  int uart_fd = Uart_Init(US_DEV_PATH, S_GETN("us-baud"));
  if (uart_fd <= 0) {
      pthread_exit(0);
  }

  // 启动一个同步写串口线程，当监听到消息时，发到串口
	pthread_t pid_uart_sync;
	pthread_create(&pid_uart_sync, NULL, &Thread_UartSync, NULL);

  char *pRecvBuf = new char[US_RECV_BUFF_LEN]; // 创建buffer
  memset(pRecvBuf, 0, US_RECV_BUFF_LEN);

  char *pSyncBuf = new char[US_RECV_BUFF_LEN]; // 创建buffer
  memset(pSyncBuf, 0, US_RECV_BUFF_LEN);

  std::mutex syncMtx; // 同步锁

  int recvCnt = 0;
  int syncCnt = 0;
  Timer recvDelayTim;
  while (1) {
    recvDelayTim.Start(100, [&]() -> bool { // 设定接收超时
      syncMtx.lock();
      if (syncCnt > 0) {
        //cout << GetSystemMs() << " >" << syncCnt << ":" << pSyncBuf << endl;
        MqttClient::GetIns()->Publish("rx", pSyncBuf, syncCnt);
        memset(pSyncBuf, 0, syncCnt);
        syncCnt = 0;
      }
      syncMtx.unlock();
      return false; // 保证定时器只进一次
    });

    int ret = Uart_Read(uart_fd, pRecvBuf+recvCnt, US_RECV_BUFF_LEN-recvCnt); // 监听串口输入
    recvDelayTim.Stop();

    if (ret < 0) {
      cout << "uart recv err: " << ret << endl;
      memset(pRecvBuf, 0, recvCnt);
      recvCnt = 0;
    } else {
      if (recvCnt > (US_RECV_BUFF_LEN>>1)) { // buf过半，才响应，避免数据包碎片化
        //cout << GetSystemMs() << " :" << recvCnt << ":" << pRecvBuf << endl;

        syncMtx.lock();
        memcpy(pSyncBuf+syncCnt, pRecvBuf, recvCnt);
        syncCnt += recvCnt;

        memset(pRecvBuf, 0, recvCnt);
        recvCnt = 0;

        MqttClient::GetIns()->Publish("rx", pSyncBuf, syncCnt);
        memset(pSyncBuf, 0, syncCnt);
        syncCnt = 0;
        syncMtx.unlock();

      } else { // 继续收包
        recvCnt += ret;
        //cout << GetSystemMs() << " +" << recvCnt << ":" << &pRecvBuf[recvCnt-ret] << endl;

        syncMtx.lock();
        memcpy(pSyncBuf+syncCnt, pRecvBuf, recvCnt);
        syncCnt += recvCnt;
        memset(pRecvBuf, 0, recvCnt);
        recvCnt = 0;
        syncMtx.unlock();

      }
    }
  }
  delete[] pRecvBuf;
  delete[] pSyncBuf;
  cout << "uart thread exit" << endl;
  pthread_exit(0);
}